
#ifndef AFTERMATH_NUMERICS_MATRIX_HPP_INCLUDED
#define AFTERMATH_NUMERICS_MATRIX_HPP_INCLUDED

#include <emmintrin.h>
#include <xmmintrin.h>

namespace aftermath
{
    namespace numerics
    {
        template <typename T>
        struct default_sse_for
        {
            typedef void type;
        };

        template <>
        struct default_sse_for<float>
        {
            typedef __m128 type;
        };

        template <>
        struct default_sse_for<double>
        {
            typedef __m128d type;
        };

        template <int M, int N, typename T, typename S = typename default_sse_for<T>::type>
        struct matrix
        {
            typedef T data_type;
            typedef S sse_type;

            static const int height = M;
            static const int width = N;

            void fill(data_type value);
            void fill_row(int row, data_type value);

            void clear();
            void clear_row(int row);

            data_type get_element(int row, int column) const;

            template <int row, int column>
            void set_element(data_type value);

            void set_element(int row, int column, data_type value);
            
            template <int row, int column>
            void clear_element();

            void clear_element(int row, int column);

            void transpose_self();
            matrix<N, M, T, S> transpose() const;

            template <int K>
            matrix<M, K, T, S> multiply(const matrix<N, K, T, S>& other) const;

            template <int K>
            matrix<M, K, T, S> fast_multiply(const matrix<N, K, T, S>& other) const;
        };
    }
}

#endif // AFTERMATH_NUMERICS_MATRIX_HPP_INCLUDED
